"""
热成像温度分析服务层
提供核心业务逻辑和数据处理功能，与GUI解耦
"""

import os
import cv2
import numpy as np
from typing import List, Dict, Any, Optional, Tuple, Callable
from dataclasses import dataclass

from ..core.temperature_mapper import TemperatureMapper
from ..core.data_storage import DataStorage
from ..core.video_stream import VideoStreamManager, validate_stream_url, convert_frame_to_qpixmap


@dataclass
class CalibrationPoint:
    """标定点数据类"""
    position: Tuple[int, int]
    hsv_color: List[float]
    temperature: float
    index: int


@dataclass
class AnalysisResult:
    """温度分析结果数据类"""
    min_temp: float
    max_temp: float
    avg_temp: float
    min_pos: Tuple[int, int]
    max_pos: Tuple[int, int]
    temp_diff: float
    pixel_count: int = 0


@dataclass
class RegionAnalysis:
    """区域分析结果数据类"""
    region_id: int
    coordinates: Dict[str, int]
    size: Dict[str, int]
    analysis_result: AnalysisResult


class ThermalAnalysisService:
    """热成像温度分析服务类
    
    提供核心的温度分析业务功能:
    - 温度标定管理
    - 图像温度分析  
    - 视频流处理
    - 数据持久化
    """
    
    def __init__(self, data_storage: Optional[DataStorage] = None):
        """
        初始化温度分析服务
        
        Args:
            data_storage: 数据存储实例，如果未提供则创建默认实例
        """
        # 核心组件
        self.temp_mapper = TemperatureMapper()
        self.data_storage = data_storage or DataStorage()
        self.stream_manager = VideoStreamManager()
        
        # 加载现有标定数据
        self._load_existing_calibration()
        
        # 图像数据
        self.current_image = None
        self.current_image_hsv = None
        self.image_source = "unknown"
        
        # 流媒体状态
        self.is_streaming = False
        self.stream_callbacks: List[Callable] = []
        
        # 标定状态
        self.calibration_mode = False
        
    # ========== 图像处理相关 ==========
    
    def load_image_from_file(self, file_path: str) -> bool:
        """
        从文件加载图像
        
        Args:
            file_path: 图像文件路径
            
        Returns:
            是否加载成功
        """
        try:
            # 使用numpy读取图片以支持中文路径
            with open(file_path, 'rb') as f:
                image_data = f.read()
            nparr = np.frombuffer(image_data, np.uint8)
            image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
            
            if image is not None:
                self.current_image = image
                self.current_image_hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
                self.image_source = f"file:{os.path.basename(file_path)}"
                return True
            return False
        except Exception:
            return False
            
    def has_image(self) -> bool:
        """检查是否有可用的图像"""
        return self.current_image is not None
        
    def get_image_info(self) -> Dict[str, Any]:
        """获取当前图像信息"""
        if not self.has_image():
            return {}
            
        height, width = self.current_image.shape[:2]
        return {
            'width': width,
            'height': height,
            'source': self.image_source,
            'has_hsv': self.current_image_hsv is not None
        }
        
    # ========== 标定管理相关 ==========
    
    def set_calibration_mode(self, enabled: bool):
        """设置标定模式"""
        self.calibration_mode = enabled
        
    def is_calibration_mode(self) -> bool:
        """检查是否处于标定模式"""
        return self.calibration_mode
        
    def add_calibration_point(self, x: int, y: int, temperature: float) -> bool:
        """
        添加标定点
        
        Args:
            x: X坐标
            y: Y坐标
            temperature: 参考温度
            
        Returns:
            是否添加成功
        """
        if not self.has_image():
            return False
            
        try:
            # 获取HSV颜色
            hsv_color = self.current_image_hsv[y, x]
            
            # 添加到温度映射器
            self.temp_mapper.add_calibration_point(hsv_color, temperature, (x, y))
            
            # 自动保存标定数据
            self.save_calibration_data()
            
            return True
        except (IndexError, ValueError):
            return False
            
    def get_calibration_points(self) -> List[CalibrationPoint]:
        """获取所有标定点信息"""
        calibration_info = self.temp_mapper.get_calibration_info()
        points = []
        
        for i, point_info in enumerate(calibration_info):
            point = CalibrationPoint(
                position=point_info['position'],
                hsv_color=point_info['hsv'],
                temperature=point_info['temperature'],
                index=i
            )
            points.append(point)
            
        return points
        
    def delete_calibration_point(self, index: int) -> bool:
        """
        删除指定索引的标定点
        
        Args:
            index: 标定点索引
            
        Returns:
            是否删除成功
        """
        calibration_points = self.temp_mapper.calibration_points.copy()
        calibration_points_with_pos = self.temp_mapper.calibration_points_with_pos.copy()
        
        if 0 <= index < len(calibration_points_with_pos):
            # 删除指定索引的标定点
            del calibration_points[index]
            del calibration_points_with_pos[index]
            
            # 更新温度映射器的数据
            self.temp_mapper.calibration_points = calibration_points
            self.temp_mapper.calibration_points_with_pos = calibration_points_with_pos
            
            # 自动保存更新后的数据
            self.save_calibration_data()
            
            return True
        return False
        
    def clear_calibration_points(self):
        """清空所有标定点"""
        self.temp_mapper.clear_calibration_points()
        # 保存清空后的状态到文件
        self.save_calibration_data()
        
    def save_calibration_data(self) -> Optional[str]:
        """
        保存标定数据
        
        Returns:
            保存的文件路径，失败返回None
        """
        try:
            calibration_points = self.temp_mapper.get_calibration_info()
            if calibration_points:
                return self.data_storage.save_calibration_data(calibration_points)
            return None
        except Exception:
            return None
            
    # ========== 温度分析相关 ==========
    
    def get_pixel_temperature(self, x: int, y: int) -> Optional[Dict[str, Any]]:
        """
        获取指定像素点的温度信息
        
        Args:
            x: X坐标
            y: Y坐标
            
        Returns:
            包含温度和颜色信息的字典
        """
        if not self.has_image():
            return None
            
        try:
            height, width = self.current_image.shape[:2]
            if x >= width or y >= height:
                return None
                
            hsv_color = self.current_image_hsv[y, x]
            bgr_color = self.current_image[y, x]
            rgb_color = (int(bgr_color[2]), int(bgr_color[1]), int(bgr_color[0]))
            temperature = self.temp_mapper.color_to_temperature(hsv_color)
            
            return {
                'position': (x, y),
                'temperature': float(temperature),
                'hsv': [int(hsv_color[0]), int(hsv_color[1]), int(hsv_color[2])],
                'rgb': rgb_color
            }
        except (IndexError, ValueError):
            return None
            
    def analyze_global_temperature(self) -> Optional[AnalysisResult]:
        """
        分析整个图像的温度分布
        
        Returns:
            全局温度分析结果
        """
        if not self.has_image():
            return None
            
        try:
            height, width = self.current_image_hsv.shape[:2]
            temp_map = np.zeros((height, width), dtype=np.float32)
            
            # 计算每个像素的温度
            for y in range(height):
                for x in range(width):
                    hsv_color = self.current_image_hsv[y, x]
                    temp_map[y, x] = self.temp_mapper.color_to_temperature(hsv_color)
                    
            # 找到最高温和最低温
            min_temp = float(np.min(temp_map))
            max_temp = float(np.max(temp_map))
            avg_temp = float(np.mean(temp_map))
            min_pos = np.unravel_index(np.argmin(temp_map), temp_map.shape)
            max_pos = np.unravel_index(np.argmax(temp_map), temp_map.shape)
            
            # 构造结果
            result = AnalysisResult(
                min_temp=min_temp,
                max_temp=max_temp,
                avg_temp=avg_temp,
                min_pos=(int(min_pos[1]), int(min_pos[0])),
                max_pos=(int(max_pos[1]), int(max_pos[0])),
                temp_diff=max_temp - min_temp,
                pixel_count=height * width
            )
            
            # 不再自动保存分析结果
            
            return result
            
        except Exception:
            return None
            
    def analyze_regions_temperature(self, regions: List[Dict[str, int]]) -> List[RegionAnalysis]:
        """
        分析指定区域的温度分布
        
        Args:
            regions: 区域坐标列表，每个区域包含x1, y1, x2, y2
            
        Returns:
            区域分析结果列表
        """
        if not self.has_image():
            return []
            
        results = []
        
        for i, region_data in enumerate(regions):
            try:
                x1, y1 = region_data['x1'], region_data['y1'] 
                x2, y2 = region_data['x2'], region_data['y2']
                
                # 提取区域温度数据
                area_temps = []
                for y in range(y1, y2):
                    for x in range(x1, x2):
                        if 0 <= x < self.current_image_hsv.shape[1] and 0 <= y < self.current_image_hsv.shape[0]:
                            hsv_color = self.current_image_hsv[y, x]
                            temp = self.temp_mapper.color_to_temperature(hsv_color)
                            area_temps.append((temp, x, y))
                            
                if area_temps:
                    # 按温度排序找到极值点
                    area_temps.sort(key=lambda item: item[0])
                    
                    min_temp_data = area_temps[0]
                    max_temp_data = area_temps[-1]
                    
                    min_temp = min_temp_data[0]
                    max_temp = max_temp_data[0]
                    avg_temp = sum(item[0] for item in area_temps) / len(area_temps)
                    
                    # 构造分析结果
                    analysis_result = AnalysisResult(
                        min_temp=min_temp,
                        max_temp=max_temp,
                        avg_temp=avg_temp,
                        min_pos=(min_temp_data[1], min_temp_data[2]),
                        max_pos=(max_temp_data[1], max_temp_data[2]),
                        temp_diff=max_temp - min_temp,
                        pixel_count=len(area_temps)
                    )
                    
                    # 构造区域分析结果
                    region_analysis = RegionAnalysis(
                        region_id=i + 1,
                        coordinates={'x1': x1, 'y1': y1, 'x2': x2, 'y2': y2},
                        size={'width': x2 - x1, 'height': y2 - y1},
                        analysis_result=analysis_result
                    )
                    
                    results.append(region_analysis)
                    
            except (KeyError, ValueError, IndexError):
                continue
                
        # 不再自动保存区域分析结果
            
        return results
        
    def save_global_analysis_result(self, result: AnalysisResult) -> Optional[str]:
        """保存全局分析结果"""
        try:
            image_info = self.get_image_info()
            save_data = {
                'image_info': image_info,
                'global_stats': {
                    'min_temp': result.min_temp,
                    'max_temp': result.max_temp,
                    'avg_temp': result.avg_temp,
                    'min_pos': result.min_pos,
                    'max_pos': result.max_pos,
                    'temp_diff': result.temp_diff
                },
                'regions': []  # 全局分析无区域数据
            }
            
            return self.data_storage.save_analysis_result(save_data)
        except Exception:
            return None
            
    def save_regions_analysis_result(self, results: List[RegionAnalysis]) -> Optional[str]:
        """保存区域分析结果"""
        try:
            image_info = self.get_image_info()
            save_data = {
                'image_info': image_info,
                'regions': []
            }
            
            # 添加区域数据
            for region in results:
                region_data = {
                    'x1': region.coordinates['x1'],
                    'y1': region.coordinates['y1'],
                    'x2': region.coordinates['x2'],
                    'y2': region.coordinates['y2'],
                    'width': region.size['width'],
                    'height': region.size['height'],
                    'stats': {
                        'min_temp': region.analysis_result.min_temp,
                        'max_temp': region.analysis_result.max_temp,
                        'avg_temp': region.analysis_result.avg_temp,
                        'temp_diff': region.analysis_result.temp_diff,
                        'min_pos': region.analysis_result.min_pos,
                        'max_pos': region.analysis_result.max_pos,
                        'pixel_count': region.analysis_result.pixel_count
                    }
                }
                save_data['regions'].append(region_data)
                
            return self.data_storage.save_analysis_result(save_data)
        except Exception:
            return None
            
    # ========== 视频流管理相关 ==========
    
    def add_stream_callback(self, callback: Callable[[np.ndarray, np.ndarray], None]):
        """添加视频流帧接收回调"""
        self.stream_callbacks.append(callback)
        
    def remove_stream_callback(self, callback: Callable):
        """移除视频流帧接收回调"""
        if callback in self.stream_callbacks:
            self.stream_callbacks.remove(callback)
            
    def start_video_stream(self, stream_url: str, fps_limit: int = 10, frame_skip: int = 1) -> bool:
        """
        启动视频流
        
        Args:
            stream_url: 流地址
            fps_limit: 帧率限制
            frame_skip: 帧跳跃数
            
        Returns:
            是否启动成功
        """
        # 验证流地址
        is_valid, _ = validate_stream_url(stream_url)
        if not is_valid:
            return False
            
        # 设置回调函数
        def frame_callback(frame_bgr, frame_hsv):
            # 更新当前帧数据
            self.current_image = frame_bgr
            self.current_image_hsv = frame_hsv
            self.image_source = f"stream:{stream_url}"
            
            # 触发用户回调
            for callback in self.stream_callbacks:
                try:
                    callback(frame_bgr, frame_hsv)
                except Exception:
                    pass
                    
        self.stream_manager.add_frame_callback(frame_callback)
        
        # 启动流
        if self.stream_manager.start_stream(stream_url, fps_limit, frame_skip):
            self.is_streaming = True
            return True
        return False
        
    def stop_video_stream(self) -> bool:
        """停止视频流"""
        try:
            self.stream_manager.stop_stream()
            self.is_streaming = False
            return True
        except Exception:
            return False
            
    def is_stream_active(self) -> bool:
        """检查视频流是否活跃"""
        return self.is_streaming
        
    # ========== 实时分析相关 ==========
    
    def perform_realtime_analysis(self) -> Optional[AnalysisResult]:
        """
        执行实时温度分析（用于流媒体模式）
        
        Returns:
            实时分析结果
        """
        if not self.has_image() or not self.is_stream_active():
            return None
            
        # 简化的实时分析，只计算基本统计信息
        try:
            height, width = self.current_image_hsv.shape[:2]
            
            # 采样分析以提高实时性能
            sample_step = max(1, min(height, width) // 50)  # 采样步长
            temp_samples = []
            
            for y in range(0, height, sample_step):
                for x in range(0, width, sample_step):
                    hsv_color = self.current_image_hsv[y, x]
                    temp = self.temp_mapper.color_to_temperature(hsv_color)
                    temp_samples.append((temp, x, y))
                    
            if temp_samples:
                temp_samples.sort(key=lambda item: item[0])
                
                min_data = temp_samples[0]
                max_data = temp_samples[-1]
                avg_temp = sum(item[0] for item in temp_samples) / len(temp_samples)
                
                return AnalysisResult(
                    min_temp=min_data[0],
                    max_temp=max_data[0],
                    avg_temp=avg_temp,
                    min_pos=(min_data[1], min_data[2]),
                    max_pos=(max_data[1], max_data[2]),
                    temp_diff=max_data[0] - min_data[0],
                    pixel_count=len(temp_samples)
                )
                
        except Exception:
            pass
            
        return None
        
    def _load_existing_calibration(self):
        """加载现有的标定数据"""
        try:
            calibration_data = self.data_storage.load_default_calibration()
            if calibration_data:
                # 清空现有标定点
                self.temp_mapper.clear_calibration_points()
                
                # 重新加载标定点
                for point in calibration_data:
                    hsv = point['hsv']
                    temp = point['temperature'] 
                    pos = point['position']
                    self.temp_mapper.add_calibration_point(hsv, temp, pos)
                    
                print(f"已加载 {len(calibration_data)} 个标定点")
        except Exception as e:
            print(f"加载标定数据失败: {e}")